/**
 *
 */
package de.cbf.cam.dsa.services.impl.rcp_provider;

import java.util.Collection;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import de.cbf.cam.dsa.rcp.model.entities.CultureDSA;
import de.cbf.cam.dsa.rcp.model.entities.ProfessionDSA;
import de.cbf.cam.dsa.rcp.model.entities.RaceDSA;
import de.cbf.cam.dsa.rcp.model.entities.StructureData;
import de.cbf.cam.dsa.services.impl.rcp_provider.extension.interfaces.IRCPPersisterStructure;
import de.cbf.cam.dsa.services.interfaces.rcp_provider.IServiceDSAProviderRCPStructure;
import de.cbf.cam.dsa.services.interfaces.rcp_provider.exceptions.ProfessionNotFoundException;
import de.cbf.cam.dsa.services.interfaces.rcp_provider.exceptions.RaceNotFoundException;
import de.cbf.util.db.interfaces.exceptions.EntityLoadException;
import de.cbf.util.db.interfaces.exceptions.EntitySaveException;
import de.cbf.util.uuidheader.entities.EntityWeighted;
import de.cbf.util.uuidheader.entities.UUIDReference;
import de.cbf.util.uuidheader.util.EntityWeightedList;
/**
 * @author Nebelritter
 */
public class ProviderRCPStructure implements IServiceDSAProviderRCPStructure{
	private static final Log logger = LogFactory.getLog(ProviderRCPStructure.class);

	private static final String NAME = "RCP Structure Test Provider";

	protected StructureData 			structureDataCached;
	protected IRCPPersisterStructure 	persister;

	public ProviderRCPStructure() {
		super();
	}

	protected StructureData getStructureDataInternal(){
		if(structureDataCached != null){
			return structureDataCached;
		}
		if(persister != null){
			try {
				StructureData combined = new StructureData();
				Collection<StructureData> datas = persister.loadAllStructureData();
				for (StructureData structureData : datas) {
					combined.mergeInRaceCultures(structureData.getRaceCultures());
					combined.mergeInCultureProfessions(structureData.getCultureProfessions());
					combined.setName(combined.getName()+structureData.getName());
				}
				this.structureDataCached = combined;//cache structure data;
				return combined;
			} catch (EntityLoadException e) {
				logger.error(e);
			}
		}
		logger.error("No structure data available, cannot provide anything");
		return new StructureData();
	}

	/* (non-Javadoc)
	 * @see de.cbf.cam.dsa.services.impl.rcp_provider.Interface#provideRacesByCulture(de.cbf.cam.dsa.rcp.model.entities.CultureDSA)
	 */
	@Override
	public EntityWeightedList provideRacesByCulture(CultureDSA culture) {
		EntityWeightedList result = new EntityWeightedList();
		UUIDReference cultureReference = UUIDReference.extractUUIDReference(culture);
		EntityWeightedList cultures = getStructureDataInternal().racesForCulture(cultureReference);
		if(cultures == null){
			//non found return empty list
			logger.warn("could not find any races for culture: "+culture );
			return result;
		}
		result.addAll(cultures);
		return result;
	}

	/* (non-Javadoc)
	 * @see de.cbf.cam.dsa.services.impl.rcp_provider.Interface#provideCulturesByRace(de.cbf.cam.dsa.rcp.model.entities.RaceDSA)
	 */
	@Override
	public EntityWeightedList provideCulturesByRace(RaceDSA race) {
		EntityWeightedList result = new EntityWeightedList();
		UUIDReference raceReference = UUIDReference.extractUUIDReference(race);
		EntityWeightedList cultures = getStructureDataInternal().culturesForRace(raceReference);
		if(cultures == null){
			//none found -> return empty list
			logger.warn("could not find any cultures for race: "+race );
			return result;
		}
		result.addAll(cultures);
		return result;
	}

	/* (non-Javadoc)
	 * @see de.cbf.cam.dsa.services.impl.rcp_provider.Interface#provideCulturesByProfession(de.cbf.cam.dsa.rcp.model.entities.ProfessionDSA)
	 */
	@Override
	public EntityWeightedList provideCulturesByProfession(ProfessionDSA profession) {
		EntityWeightedList result = new EntityWeightedList();
		UUIDReference professionReference = UUIDReference.extractUUIDReference(profession);
		EntityWeightedList cultures = getStructureDataInternal().culturesForProfession(professionReference);
		if(cultures == null){
			//non found return empty list
			logger.warn("could not find any cultures for profession: "+profession );
			return result;
		}
		result.addAll(cultures);
		return result;
	}

	/* (non-Javadoc)
	 * @see de.cbf.cam.dsa.person.db.IProviderRCPStructure#getProfessionsByCulture(de.cbf.cam.dsa.person.entities.CultureDSA)
	 */
	/* (non-Javadoc)
	 * @see de.cbf.cam.dsa.services.impl.rcp_provider.Interface#provideProfessionsByCulture(de.cbf.cam.dsa.rcp.model.entities.CultureDSA)
	 */
	@Override
	public EntityWeightedList provideProfessionsByCulture(CultureDSA culture) {
		EntityWeightedList result = new EntityWeightedList();
		UUIDReference cultureReference = UUIDReference.extractUUIDReference(culture);
		EntityWeightedList cultures = getStructureDataInternal().professionsForCulture(cultureReference);
		if(cultures == null){
			//non found return empty list
			logger.warn("could not find any professions for culture: "+culture );
			return result;
		}
		result.addAll(cultures);
		return result;
	}



	/* (non-Javadoc)
	 * @see de.cbf.cam.dsa.services.interfaces.rcp_provider.IServiceDSAProviderRCPStructure#provideRacesByProfession(de.cbf.cam.dsa.rcp.model.entities.ProfessionDSA)
	 */
	/* (non-Javadoc)
	 * @see de.cbf.cam.dsa.services.impl.rcp_provider.Interface#provideRacesByProfession(de.cbf.cam.dsa.rcp.model.entities.ProfessionDSA)
	 */
	@Override
	public EntityWeightedList provideRacesByProfession(ProfessionDSA profession) throws RaceNotFoundException {
		if(profession == null){
			throw new RaceNotFoundException("profession not set");
		}
		// get cultures by profession and sum up races without doubling
		EntityWeightedList result = new EntityWeightedList();
		//get all cultures for profession
		EntityWeightedList cultures = provideCulturesByProfession(profession);
		for (EntityWeighted cultureDSAWeighted : cultures) {
			//for each culture get the possible and usual races
			CultureDSA culture = (CultureDSA)cultureDSAWeighted.getEntity();
			result.mergeList(provideRacesByCulture(culture), EntityWeightedList.BEHAVIOUR_LIST_ADD, EntityWeightedList.BEHAVIOR_WEIGHTS_ADD);
		}
		return result;
	}

	/* (non-Javadoc)
	 * @see de.cbf.cam.dsa.services.interfaces.rcp_provider.IServiceDSAProviderRCPStructure#provideProfessionsByRace(de.cbf.cam.dsa.rcp.model.entities.RaceDSA)
	 */
	/* (non-Javadoc)
	 * @see de.cbf.cam.dsa.services.impl.rcp_provider.Interface#provideProfessionsByRace(de.cbf.cam.dsa.rcp.model.entities.RaceDSA)
	 */
	@Override
	public EntityWeightedList provideProfessionsByRace(RaceDSA race)throws ProfessionNotFoundException {
		if(race == null){
			throw new ProfessionNotFoundException("race not set");
		}
		// get cultures by profession and sum up races without doubling
		EntityWeightedList result = new EntityWeightedList();

		//get all cultures for race
		EntityWeightedList cultures = provideCulturesByRace(race);

		for (EntityWeighted entityWeighted : cultures) {
			if (entityWeighted.getEntity() instanceof CultureDSA) {
				CultureDSA culture = (CultureDSA) entityWeighted.getEntity();
				//find professions for each culture
				EntityWeightedList cultureProfessions = provideProfessionsByCulture(culture);
				//add new professions to defaultWeights collection
				result.mergeList(cultureProfessions, EntityWeightedList.BEHAVIOR_WEIGHTS_ADD,EntityWeightedList.BEHAVIOR_WEIGHTS_MIDDLE);
			}
		}
		return result;
	}

	@Override
	public void persistStructure(StructureData entity) {
		try {
			persister.saveStructure(entity);
		} catch (EntitySaveException e) {
			e.printStackTrace();
		}
	}

	@Override
	public String getName() {
		return NAME;
	}

	public StructureData getStructureData() {
		return structureDataCached;
	}

	/**
	 * @param structureDataCached
	 * may be set null, if structure is to be saved by persister, make sure persister is set
	*/
	public void setStructureData(StructureData structureData, boolean persist) {
		this.structureDataCached = structureData;
		if (persist && persister != null) {
			try {
				persister.saveStructure(structureData);
			} catch (EntitySaveException e) {
				logger.error(e);
			}
		}
	}

	public IRCPPersisterStructure getPersister() {
		return persister;
	}

	public void setPersister(IRCPPersisterStructure persister) {
		this.persister = persister;
		if(persister != null){
			structureDataCached = null;//set null to reload structure data from new persister
			getStructureDataInternal();
		}
	}




}

